package com.quark.framework.database;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Savepoint;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;

import com.quark.data.processor.QuarkDataArrayProcessor;
import com.quark.framework.ormapping.QuarkOrmEntity;
import com.quark.framework.utility.QuarkLog;

public class QuarkDBExecuteManager {

	private static QuarkDBMetaDataManager metaManager = null;
	private boolean isTransactionSupported = false;
	private QuarkDBPooledConnection conn = null;
	private Statement stm = null;
	private Map<String, Savepoint> savePointMapping = new HashMap<String, Savepoint>();
	protected QuarkDBExecuteManager()
	{
		
	}
		
	public boolean init(QuarkDBMetaDataManager meta)
	{
		metaManager = meta;
		return true;
	}
	
	public boolean beginTransaction()
	{
		if(!isTransactionSupported)
			return false;
		conn = QuarkDBConnectionPool.getInstance().getBestConnection();
		return conn != null;
	}
	
	public boolean endTransaction()
	{
		if(!isTransactionSupported)
			return false;
		String name = getTransactionName();
		Savepoint savepoint = savePointMapping.get(name);
		if(savepoint != null)
		{
			try {
				conn.getConnection().releaseSavepoint(savepoint);
			} catch (SQLException e) {
				// TODO Auto-generated catch block
				QuarkLog.log(e);
			}
		}
		return true;
	}
	
	private synchronized String getTransactionName()
	{
		return "ThreadTransaction" + Thread.currentThread().getId(); 
	}
	
	public boolean uninit()
	{
		if(!QuarkDBConnectionPool.getInstance().uninit())
			return false;
		
		return true;
	}

	protected synchronized boolean supportTransaction()
	{
		return isTransactionSupported;
	}
	
	protected synchronized void setTransactionSupport(boolean isSupported)
	{
		isTransactionSupported = isSupported;
	}
	
	private void recycle()
	{
		conn.returnStatement(stm);
		QuarkDBConnectionPool.getInstance().returnConnection(conn);
	}
		
	public QuarkOrmEntity[] doGeneralQuery(Class<? extends QuarkOrmEntity> entity, String sql)
	{
		conn = QuarkDBConnectionPool.getInstance().getBestConnection();
		stm = conn.getStatement();
		try {
			ArrayList<QuarkOrmEntity> list = new ArrayList<QuarkOrmEntity>();			
			ResultSet rst = stm.executeQuery(sql);
			int count = 0;
			while(rst.next())
			{
				try {
					QuarkOrmEntity orm = entity.newInstance();
					orm.fromResultSet(rst);
					orm.doAfterSelect();
					list.add(orm);
					count ++;
				} catch (InstantiationException e) {
					// TODO Auto-generated catch block
					QuarkLog.log(e);
				} catch (IllegalAccessException e) {
					// TODO Auto-generated catch block
					QuarkLog.log(e);
				}
			}
			return list.toArray(new QuarkOrmEntity[count]);
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			QuarkLog.log(e);
			return null;
		} finally
		{			
			recycle();
		}
	}
	
	public QuarkOrmEntity[] doSelect(Class<? extends QuarkOrmEntity> entity, String limit)
	{
		String sql = QuarkDBSqlHelper.createSelect(entity, limit);		
		if(sql != null)
			return doGeneralQuery(entity, sql);
		return null;
	}
	
	public QuarkOrmEntity[] doSelect(Class<? extends QuarkOrmEntity> base, String[] fields, String limit, String sortBy, String startIndex, String fetchCount, boolean desc)
	{
		String sql = QuarkDBSqlHelper.createSelect(base, fields, limit, sortBy, startIndex, fetchCount, desc);
		if(sql != null)
			return doGeneralQuery(base, sql);
		return null;
	}
		
	public QuarkOrmEntity doSelectOne(Class<? extends QuarkOrmEntity> entity, String limit)
	{
		QuarkOrmEntity[] result = doSelect(entity, limit);
		if(result != null && result.length > 0)
			return result[0];
		return null;
	}
	
	public int doGeneralUpdate(String sql)
	{
		if(!supportTransaction())
		{
			conn = QuarkDBConnectionPool.getInstance().getBestConnection();
		}else
		{
			if(conn == null)
				conn = QuarkDBConnectionPool.getInstance().getBestConnection();
		}
		
		stm = conn.getStatement();
		String name = getTransactionName();
		if(!savePointMapping.containsKey(name))
		{
			try {
				savePointMapping.put(name, conn.getConnection().setSavepoint(name));
			} catch (SQLException e) {
				// TODO Auto-generated catch block
				QuarkLog.log(e);
			}
		}
		int count = -1;
		try
		{
			count = stm.executeUpdate(sql);
		}catch(Exception e)
		{
			QuarkLog.log(e);
		}finally
		{		
			if(!supportTransaction())
			{
				recycle();
			}
		}
		return count;		
	}
	
	public int[] doGeneralUpdate(String[] sql)
	{
		if(!supportTransaction())
		{
			conn = QuarkDBConnectionPool.getInstance().getBestConnection();
		}else
		{
			if(conn == null)
				conn = QuarkDBConnectionPool.getInstance().getBestConnection();
		}
		
		stm = conn.getStatement();
		String name = getTransactionName();
		if(!savePointMapping.containsKey(name))
		{
			try {
				savePointMapping.put(name, conn.getConnection().setSavepoint(name));
			} catch (SQLException e) {
				// TODO Auto-generated catch block
				QuarkLog.log(e);
			}
		}
		int[] count = null;
		try
		{
			stm.clearBatch();
			for(int i = 0; i < sql.length; i ++)
			{
				if(sql[i] != null)
					stm.addBatch(sql[i]);
			}
			count = stm.executeBatch();
		}catch(Exception e)
		{
			QuarkLog.log(e);
		}finally
		{		
			if(!supportTransaction())
			{
				recycle();
			}
		}
		return count;
	}
	public int doInsert(QuarkOrmEntity entity)
	{
		int res = -1;
		if(!entity.doBeforeInsert())
			return res;
		String sql = QuarkDBSqlHelper.createInsert(entity);		
		if(sql != null)
		{			
			res = doGeneralUpdate(sql);
			if(res != -1)
				//success
			{
				entity.doAfterInsert();
			}
		}
		return res;
	}
	
	public int doInsert(QuarkOrmEntity[] entities)
	{
		int res = -1;
		for(int i = 0; i < entities.length; i ++)
		{
			if(!entities[i].doBeforeInsert())
				return res;
		}
		String sql = QuarkDBSqlHelper.createInsert(entities);		
		if(sql != null)
		{
			res = doGeneralUpdate(sql);
			if (res != -1)
				//success
			{
				for(int i = 0; i < entities.length; i ++)
				{
					entities[i].doAfterInsert();
				}				
			}
		}
		return res;
	}
	
	public int doUpdate(QuarkOrmEntity entity)
	{
		int res = -1;
		if(!entity.doBeforeUpdate())
			return res;
		String sql = QuarkDBSqlHelper.createUpdate(entity);		
		if (!entity.doBeforeInsert())
			return res;
		if(sql != null)
		{
			res = doGeneralUpdate(sql);
			if(res != -1)
			{
				entity.doAfterUpdate();
			}
		}
		return res;
	}
	
	public int doUpdate(QuarkOrmEntity[] entity)
	{
		int res = -1;
		for(int i = 0; i < entity.length; i ++)
		{
			if(!entity[i].doBeforeUpdate())
				return res;
		}
		String[] sql = QuarkDBSqlHelper.createUpdate(entity);
		if(sql != null)
		{
			res = QuarkDataArrayProcessor.sumArray(doGeneralUpdate(sql));
			if(res != -1)
			{
				for(int i = 0; i < entity.length; i ++)
				{
					entity[i].doAfterUpdate();
				}				
			}
		}		
		return res;
	}
	
	public int doReplace(QuarkOrmEntity[] entities)
	{
		int res = -1;
		for(int i = 0; i < entities.length; i ++)
		{
			if(!entities[i].doBeforeReplace())
				return res;
		}
		String sql = QuarkDBSqlHelper.createReplace(entities);
		if(sql != null)
		{
			res = doGeneralUpdate(sql);
			if(res != -1)
			{
				for(int i = 0; i < entities.length; i ++)
				{
					entities[i].doAfterReplace();
				}				
			}
		}		
		return res;
	}
	
	public int doInsertIfNotExist(QuarkOrmEntity entity)
	{
		
		String sql = QuarkDBSqlHelper.createInsertIfNotExist(entity);
		if(sql != null)
		{
			return doGeneralUpdate(sql);
		}
		return 0;
	}
	
	public int doInsertIfNotExist(QuarkOrmEntity[] entity)
	{
		int res = -1;
		for(int i = 0; i < entity.length; i ++)
		{
			if(!entity[i].doBeforeInsert())
				return res;
		}
		String[] sql = QuarkDBSqlHelper.createInsertIfNotExist(entity);
		if(sql != null)
		{
			int[] resArr = doGeneralUpdate(sql);
			if (resArr != null)
				//success
			{
				res = QuarkDataArrayProcessor.sumArray(resArr);
				for(int i = 0; i < entity.length; i ++)
				{
					entity[i].doAfterInsert();
				}
			}
		}
		return res;
	}
	
	public int doDelete(QuarkOrmEntity entity)
	{
		entity.doBeforeDelete();
		String sql = QuarkDBSqlHelper.createDelete(entity);
		if(sql != null)
			return doGeneralUpdate(sql);
		return -1;
	}
	
	public int doDelete(QuarkOrmEntity entity[])
	{
		int res = -1;
		for(int i = 0; i < entity.length; i ++)
		{
			if(!entity[i].doBeforeDelete())
				return res;
		}
		String sql = QuarkDBSqlHelper.createDelete(entity);
		if(sql != null)
			return doGeneralUpdate(sql);
		return res;
	}
	
	public int doDelete(Class<? extends QuarkOrmEntity> entity, String limit)
	{
		String sql = QuarkDBSqlHelper.createDelete(entity, limit);
		if(sql != null)
			return doGeneralUpdate(sql);
		return 0;
	}
	
	public int doGetCount(Class<? extends QuarkOrmEntity> entity)
	{
		String sql = QuarkDBSqlHelper.createGetCount(entity);
		int count = 0;
		conn = QuarkDBConnectionPool.getInstance().getBestConnection();
		stm = conn.getStatement();
		try {			
			ResultSet rst = stm.executeQuery(sql);			
			if(!rst.next())
				return 0;
			count = rst.getInt("COUNT(*)");
		}
		catch(Exception e)
		{
			QuarkLog.log(e);
		}
		recycle();
		return count;
	}
	
	public int doGetCount(Class<? extends QuarkOrmEntity> entity, String limit)
	{
		String sql = QuarkDBSqlHelper.createGetCount(entity) + " WHERE " + limit;
		int count = 0;
		conn = QuarkDBConnectionPool.getInstance().getBestConnection();
		stm = conn.getStatement();
		try {			
			ResultSet rst = stm.executeQuery(sql);			
			if(!rst.next())
				return 0;
			count = rst.getInt("COUNT(*)");
		}
		catch(Exception e)
		{
			QuarkLog.log(e);
		}
		recycle();
		return count;
	}
	
}
